package com.example.java_gobang.api;

import com.example.java_gobang.game.MatchRequest;
import com.example.java_gobang.game.MatchResponse;
import com.example.java_gobang.game.Matcher;
import com.example.java_gobang.game.OnlineUserManager;
import com.example.java_gobang.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

//通过这个类来处理匹配功能中的 websocket 请求
@Component
public class MatchAPI extends TextWebSocketHandler {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private Matcher matcher;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //玩家上线,加入到 OnlineUserManager 中

        //1.先获取到当前用户的身份信息(谁在游戏大厅中,建立的连接)
        //  此处代码之所以能够 getAttributes, 是因为在注册 WebSocket 时,
        //  加上了 addInterceptors(new HttpSessionHandshakeInterceptor());
        //  这个逻辑就把 HttpSession 中的 Attribute 都拿到 WebSocketSession 中了
        //  在登录的逻辑中,httpSession.setAttribute("user", user); 往httpSession中存储了User 数据
        //  此时就可以在 WebSocketSession中把之前在httpSession存的User 对象给拿到了

        //注意,如果之前用户没有通过HTTP 来进行登录, 而是直接通过 /game_hall.html这个url来访问游戏大厅页面
        //此时就会出现user 为null的情况
        try {
            User user = (User) session.getAttributes().get("user");

            //2.先判定当前用户是否已经登录过(在线状态), 如果在线,就不应该继续后续的逻辑
            if(onlineUserManager.getFromGameHall(user.getUserId()) != null
            || onlineUserManager.getFromGameRoom(user.getUserId()) != null){
                //当前用户已经登录了
                //针对这个情况要告诉客户端,你这里重复登录了
                MatchResponse response = new MatchResponse();
                response.setOk(true);
                response.setReason("当前禁止多开!");
                response.setMessage("repeatConnection");
                // 先将response通过objectMapper转成json字符串,再通过TextMessage将其包装成一个文本类型的websocket数据包
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
                //此处直接关闭有些太激进了, 还是返回一个特殊的message, 供客户端来进行判定,有客户端进行处理
//                session.close();//主动关闭连接, 同时会触发afterConnectionClosed
                return;
            }

            //3.拿到身份信息之后, 就可以把玩家设置成在线状态
            onlineUserManager.enterGameHall(user.getUserId(), session);
            System.out.println("玩家"+ user.getUsername() + "进入游戏大厅");
        } catch (NullPointerException e) {
            System.out.println("[MatchAPI.afterConnectionEstablished]当前用户未登录");

            //e.printStackTrace();
            //出现空指针异常,说明当前用户的信息是空,用户未登录
            //把当前用户未登录这个信息返回去
            MatchResponse response = new MatchResponse();
            response.setOk(false);
            response.setReason("您尚未登录! 不能进行后续匹配");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        User user = (User) session.getAttributes().get("user");
        //获取到客户端给服务器发送的数据
        String payload = message.getPayload();
        //当前这个数据载荷是一个 JSON 格式的字符串, 需要把它转成 Java 对象. MatchRequest
        MatchRequest request = objectMapper.readValue(payload, MatchRequest.class);
        MatchResponse response = new MatchResponse();
        if(request.getMessage().equals("startMatch")){
            //进入匹配队列
            //TODO 先创建一个类表示匹配队列,把当前用户加进去
            matcher.add(user);
            //把玩家信息放入匹配队列之后, 就可以返回一个响应给客户端了
            response.setOk(true);
            response.setMessage("startMatch");
        }else if (request.getMessage().equals("stopMatch")){
            //退出匹配队列
            //TODO 先创建一个类表示匹配队列,把当前用户移除
            matcher.remove(user);
            //移除之后,就可以返回一个响应给客户端了
            response.setOk(true);
            response.setMessage("stopMatch");
        } else {
            response.setOk(false);
            response.setReason("非法的匹配请求");
        }
        //将打包好的数据响应 发送给客户端
        String jsonString = objectMapper.writeValueAsString(response);
        session.sendMessage(new TextMessage(jsonString));

    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        try {
            //玩家下线, 从 OnlineUserManager 中删除
            User user = (User) session.getAttributes().get("user");
            WebSocketSession tmpSession = onlineUserManager.getFromGameHall(user.getUserId());
            if(tmpSession == session){
                onlineUserManager.exitGameHall(user.getUserId());
            }
            //如果玩家正在匹配中,而 websocket 连接断开了, 就应该移除匹配队列
            matcher.remove(user);
        } catch (NullPointerException e) {
            System.out.println("[MatchAPI.handleTransportError]当前用户未登录");

//            e.printStackTrace();
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("您尚未登录! 不能进行后续匹配");
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }

    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        try {
            //玩家下线, 从 OnlineUserManager 中删除
            User user = (User) session.getAttributes().get("user");

            WebSocketSession tmpSession = onlineUserManager.getFromGameHall(user.getUserId());
            //判断是否是第二个用户重复登录, 防止误伤第一个已经登录在线的用户
            if(tmpSession == session){
                onlineUserManager.exitGameHall(user.getUserId());
            }
            //如果玩家正在匹配中,而 websocket 连接断开了, 就应该移除匹配队列
            matcher.remove(user);

        } catch (NullPointerException e) {
            System.out.println("[MatchAPI.afterConnectionClosed]当前用户未登录");
//            e.printStackTrace();
            //不应该再消息关闭了之后在 发消息给客户端
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("您尚未登录! 不能进行后续匹配");
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }
}
